﻿using PLCS.Domain.Orders;
using PLCS.Domain.Processes;
using PLCS.Domain.Shared.Processes;
using PLCS.Domain.Shared.Tasks;
using PLCS.EquipmentService.ParsersHelpers;
using PLCS.Shared.Common.Constant;

namespace PLCS.EquipmentService.BackgroundWorks.Analysis;

[DisallowConcurrentExecution] // 禁止并行操作特性
internal class ProcessAnalysisWorker : QuartzBackgroundWorkerBase
{
    private readonly IRepository<OrderRunningCondition> _orderRunningConditionRepository;
    private readonly IProcessRepository _processRepository;
    private readonly IOrderRepository _orderRepository;
    private readonly ITaskRepository _taskRepository;
    private readonly IStationRepository _stationRepository;
    private readonly IHisTaskRepository _hisTaskRepository;
    private readonly IRepository<Instruction, Guid> _instructionRepository;
    private readonly PathAnalyzer _dataAnalyzer;
    private readonly TaskManager _taskManager;

    public ProcessAnalysisWorker(IRepository<OrderRunningCondition> orderRunningConditionRepository,
        IProcessRepository processRepository,
        IOrderRepository orderRepository,
        ITaskRepository taskRepository,
        IStationRepository stationRepository,
        IHisTaskRepository hisTaskRepository,
        IRepository<Instruction, Guid> instructionRepository,
        PathAnalyzer dataAnalyzer,
        TaskManager taskManager)
    {
        _orderRunningConditionRepository = orderRunningConditionRepository;
        _processRepository = processRepository;
        _orderRepository = orderRepository;
        _taskRepository = taskRepository;
        _stationRepository = stationRepository;
        _hisTaskRepository = hisTaskRepository;
        _instructionRepository = instructionRepository;
        _dataAnalyzer = dataAnalyzer;
        _taskManager = taskManager;
        JobDetail = JobBuilder.Create<ProcessAnalysisWorker>().WithIdentity(nameof(ProcessAnalysisWorker)).Build();
        Trigger = TriggerBuilder.Create().WithIdentity(nameof(ProcessAnalysisWorker))
            .WithSimpleSchedule(s => s.WithIntervalInSeconds(1)
            .RepeatForever()
            .WithMisfireHandlingInstructionIgnoreMisfires())
            .Build();

        ScheduleJob = async scheduler =>
        {
            if (!await scheduler.CheckExists(JobDetail.Key) && LocalConfigManager.IsProcessAnalysis)
            {
                await scheduler.ScheduleJob(JobDetail, Trigger);
            }
        };
    }

    public override async Task Execute(IJobExecutionContext context)
    {
        // 先找到所有未执行的工单工序情况
        var orderRunningConditions = (await _orderRunningConditionRepository.GetListAsync(x => x.ProcessStatus == ProcessStatus.未执行)).OrderBy(x => x.WhichStep);

        foreach (var orderRunningCondition in orderRunningConditions)
        {
            var order = await _orderRepository.FindAsync(x => x.OrderNo == orderRunningCondition.OrderNo);
            if (order == null)
                continue;
            var runningConditions = await _orderRunningConditionRepository.GetListAsync(x => x.ProcessStatus == ProcessStatus.执行中 && x.OrderNo == order.OrderNo);
            // 判断同一个订单下，是否已存在正在执行的步骤
            if (runningConditions.Any()) continue;
            // 上一个工序的目标位 默认是上限工位
            string lastProcessToPos = order.OnlineStation;

            if (orderRunningCondition.WhichStep != 1)
            {
                // 找到上一个工序的目标位
                var lastorderRunningCondition = await _orderRunningConditionRepository.GetAsync(x => x.WhichStep == orderRunningCondition.WhichStep - 1 && x.OrderNo == orderRunningCondition.OrderNo);

                //判断是否放行
                if (!lastorderRunningCondition.IsPermit)
                    continue;

                var lasProcess = await _processRepository.GetAsync(x => x.ProcessNo == lastorderRunningCondition.ProcessNo);
                lastProcessToPos = lasProcess.TargetPos;
            }

            // 获取当前工序
            var process = await _processRepository.FindAsync(x => x.ProcessNo == orderRunningCondition.ProcessNo);

            if (process == null) continue;

            //获取可行的工位
            string targetPos = await GetFeasibleTargetPosAsync(process.TargetPos);
            var task = new TaskModel(0, 0, lastProcessToPos, targetPos, "", TaskType.普通流转, "工序生成", order.TrayNo, order.OrderNo, process.BeforeExecutionMethod, null, process.AfterExecutionMethod, null);
            orderRunningCondition.ChangeStatus(ProcessStatus.执行中);
            await _orderRunningConditionRepository.UpdateAsync(orderRunningCondition);
            await _taskManager.InsertAsync(task);
        }
    }

    /// <summary>
    /// 工序目标位可能会有多个，需要先得到出可进的工位。（目前只判断了目标位的空满位，后期可以根据别的，继续优化）
    /// </summary>
    /// <param name="targetPosListString">多个工位的字符串，用，拼接</param>
    /// <returns></returns>
    private async Task<string> GetFeasibleTargetPosAsync(string targetPosListString)
    {
        var targetPoses = targetPosListString.Split(ConstantChar.SplitChar);
        string targetPos = targetPoses[0];
        foreach (var targetPosesItem in targetPoses)
        {
            var station = await _stationRepository.GetAsync(x => x.StaName == targetPosesItem);
            if (station.HaveStatus == YesNo.否)
            {
                targetPos = targetPosesItem;
                break;
            }
        }
        return targetPos;
    }
}